Skip to content

fix(ttx): revert IsMe gate — breaks after vault-wiping restart#1564

Open
atharrva01 wants to merge 6 commits into
hyperledger-labs:mainfrom
atharrva01:fix/collect-endorsements-signer-is-me-gate
Open

fix(ttx): revert IsMe gate — breaks after vault-wiping restart#1564
atharrva01 wants to merge 6 commits into
hyperledger-labs:mainfrom
atharrva01:fix/collect-endorsements-signer-is-me-gate

Conversation

@atharrva01
Copy link
Copy Markdown
Contributor

@atharrva01 atharrva01 commented Apr 17, 2026

Closes #1226

Originally this PR gated GetSigner() behind IsMe() to avoid an expensive sign-and-verify round trip inside DeserializeSigningIdentity for remote idemix identities.

That optimization turned out to break zkatdlog integration tests: when a node restarts with vault deletion, the DB is wiped, IsMe() returns false for every identity (including the node's own token owners), local signing gets skipped, and the idemix ZK proof fails with contribution is not zero.

Meanwhile, the expensive sign-and-verify inside DeserializeSigningIdentity was independently removed in b43ba2b , so the motivation for the gate is gone too.

Fix: revert to unconditional GetSigner(). For remote identities it fails fast with a CSP key-not-found; for local ones it signs correctly regardless of DB state. Also persists signer info for the typed alias in RegisterIdentityDescriptor so IsMe() stays correct across restarts even when used elsewhere.

@atharrva01
Copy link
Copy Markdown
Contributor Author

hi @adecaro , I gated GetSigner() behind IsMe() to skip unnecessary idemix crypto costs for remote identities.

@adecaro adecaro force-pushed the fix/collect-endorsements-signer-is-me-gate branch from 59e2fcc to f5bf435 Compare April 23, 2026 12:50
@adecaro
Copy link
Copy Markdown
Contributor

adecaro commented Apr 23, 2026

Hi @atharrva01 , thank you for submitting this and sorry for the late reply 🙏

I'll review ASAP. I'm curious to look at your approach more carefully 😄

@adecaro adecaro self-assigned this Apr 23, 2026
@adecaro adecaro added this to the Q2/26 milestone Apr 23, 2026
@adecaro adecaro force-pushed the fix/collect-endorsements-signer-is-me-gate branch from f5bf435 to 6417f23 Compare May 4, 2026 09:46
@adecaro
Copy link
Copy Markdown
Contributor

adecaro commented May 4, 2026

Hi @atharrva01 , apologies for this late reply. I just want to double check the semantic.
I'm not sure if we are solving the problem. That code that uses the signatures might still be needed.

@atharrva01
Copy link
Copy Markdown
Contributor Author

atharrva01 commented May 4, 2026

Hi @adecaro! You're right to flag this.

The issue is that IsMe() relies on GetExistingSignerInfo, which only tracks identities where StoreSignerInfo was previously called, and that only happens inside a successful GetSigner(). RegisterIdentityDescriptor (called at wallet init) writes to a separate table and populates the in-memory cache, but not the signer-info row. So after a restart, IsMe() can return false for a locally-owned identity that hasn't been through GetSigner() in the current process, causing the gate to skip local signing incorrectly.

I fixed it by calling StoreSignerInfo inside RegisterIdentityDescriptor when the descriptor has a signer, so IsMe() stays accurate across restarts.

Also, for idemixnym identities specifically, DeserializeSigner calls GetSignerInfo first and fails fast before any crypto for remote identities, so the expensive sign-and-verify was only being hit for raw idemix, not pseudonyms. The gate still cuts that cost.

All identity and ttx tests pass.

@adecaro
Copy link
Copy Markdown
Contributor

adecaro commented May 12, 2026

Hi @atharrva01 , I think we are still not there. We need to check the function DeserializeSigningIdentity in token/services/identity/idemix/km.go. That function generates a signature and verifies it against the issuer public key to make sure the deserialized signer is good with the respect to the issuer public key inside the deserializer.
Now, I think we don't need that check anymore because in

func (p *KeyManager) DeserializeSigningIdentity(ctx context.Context, raw []byte) (tdriver.SigningIdentity, error) {
	id, err := p.Deserialize(ctx, raw)
	if err != nil {
		return nil, err
	}

p.Deserialize, the code verifies the identity itself against the issuer public key.

So, I would start with a unit-test that checks that p.Deserialize fails when given an identity that is valid under a different idemix issuer public key. If this is case, then I would remove the code that generates the ephemeral signature and see if the integration tests are still happy in the CI. If unit-tests fail to show that p.Deserialize is enough to tell apart a valid identity, then, we need to check if there is some other way to optmize the code.

What do you think?

…edger-labs#1226)

Gate GetSigner() behind a cheap IsMe() check to skip the expensive
idemix sign-and-verify deserialization for remote identities.

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
… testifylint

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
…e is correct after restart

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
…Identity

p.Deserialize already verifies the ZK association proof against the issuer
public key, which is sufficient to reject identities from a different issuer.
The ephemeral sign-and-verify liveness check is no longer needed.

Added TestDeserialize_RejectsDifferentIssuerIdentity to prove p.Deserialize
fails for different-issuer identities before any signing identity is built.

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
@atharrva01 atharrva01 force-pushed the fix/collect-endorsements-signer-is-me-gate branch from f4c758d to 53b0579 Compare May 15, 2026 17:28
@atharrva01
Copy link
Copy Markdown
Contributor Author

@adecaro, implemented the suggested approach.

Added a unit test (TestDeserialize_RejectsDifferentIssuerIdentity) confirming that p.Deserialize already rejects identities from a different issuer via verifyProof(), returning cannot deserialize, invalid identity.
Removed the temporary Sign+Verify block from DeserializeSigningIdentity.

One thing I noticed: identities from the same issuer but belonging to another user now deserialize successfully, since ownership of the nym key is no longer checked there. In a real deployment, Sign would still fail because the local CSP does not have the corresponding nym secret key.

That’s why I kept the earlier IsMe guard, without it, same-issuer remote signers end up causing transaction failures instead of falling back to remote signing. Happy to adjust if you’d prefer a different direction.

After a node restart the in-memory signers cache is empty, so IsMe()
falls back to GetExistingSignerInfo in storage. RegisterIdentityDescriptor
was only persisting the raw identity via StoreSignerInfo, but tokens store
the typed (alias) identity as their owner. On restart IsMe(typedIdent)
returned false, the IsMe gate in collectendorsements skipped local signing,
and the transfer ended with a chaincode-rejected ZK proof.

Fix: also call StoreSignerInfo for the alias when it is set, mirroring
what updateCaches already does in memory for both raw and alias keys.

This is the root cause of all dlog CI failures on this branch: every
failing test suite restarts at least one node before the transfer under
test, while the passing suites do not.

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
…removal

DeserializeSigningIdentity no longer runs a sign-and-verify round-trip
(removed in b43ba2b), so the IsMe gate that was added to avoid that
expense is no longer necessary.

More critically, the gate breaks after a vault-wiping restart: the DB is
wiped, IsMe() returns false for all identities (including the node's own
token owners), local signing is skipped, and the idemix ZK proof fails
with "contribution is not zero" because the wrong code path is taken.

Revert to unconditional GetSigner(): for remote identities it fails fast
with a CSP key-not-found, same as before, and for local identities it
correctly signs regardless of whether the DB has been wiped.

Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
@atharrva01 atharrva01 changed the title fix(ttx): avoid GetSigner for remote identities via IsMe gate fix(ttx): revert IsMe gate — breaks after vault-wiping restart May 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve CollectEndorsementsView's handling of signers

2 participants